/* 
 * ChamatecUtil.java
 * Copyright (c) Faculdade Anhanguera de Anápolis.
 * Tecnologia em Análise e Desenvolvimento de Sistemas.
 * Projeto Multidisciplinar de Autoaprendizagem.
 *
 * Este software é confidencial e propriedade da Faculdade Anhanguera de Anápolis.
 * Não é permitida sua distribuição ou divulgação do seu conteúdo sem expressa autorização da Faculdade Anhanguera de Anápolis.
 * Este arquivo contém informações proprietárias.
 */
package br.com.pma.chamatec.util;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.KeyManagementException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.util.Properties;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeUtility;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import br.com.pma.chamatec.exception.ChamatecExceptionCode;
import br.com.pma.chamatec.exception.ChamatecNegocioException;
import br.com.pma.chamatec.vo.EmailVO;

/**
 * Classe Utilitária do sistema Chamatec.
 *
 * @author Ludemeula Fernandes de Sá
 */
public abstract class ChamatecUtil {

	private static Properties prop = null;
	private static byte[] salt = { (byte) 0xA9, (byte) 0x9B, (byte) 0xC8, (byte) 0x32, (byte) 0x56, (byte) 0x34, (byte) 0xE3, (byte) 0x03 };
	private static int iterationCount = 19;
	private static String passPhrase = "key_inter";

	/**
	 * Metodo para enviarEmail utilizando Exchange
	 * 
	 * @param emailVO
	 * @throws MessagingException
	 * @throws UnsupportedEncodingException
	 * @throws ChamatecNegocioException
	 */
	public static void enviarEmailExchange(final EmailVO emailVO) throws MessagingException, UnsupportedEncodingException, ChamatecNegocioException {
		if (emailVO.isAceitaCertificadoInvalido()) {
			final TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
				public void checkClientTrusted(final X509Certificate[] chain, final String authType) {
				}

				public void checkServerTrusted(final X509Certificate[] chain, final String authType) {
				}

				public X509Certificate[] getAcceptedIssuers() {
					return null;
				}
			} };

			try {
				SSLContext ctx = SSLContext.getInstance("TLS");
				ctx.init(new KeyManager[0], trustAllCerts, new SecureRandom());
				SSLContext.setDefault(ctx);
			} catch (KeyManagementException e1) {
				e1.printStackTrace();
				throw new ChamatecNegocioException(ChamatecExceptionCode.ERRO_ENVIO_EMAIL);
			} catch (NoSuchAlgorithmException e) {
				e.printStackTrace();
				throw new ChamatecNegocioException(ChamatecExceptionCode.ERRO_ENVIO_EMAIL);
			}
		}

		InternetAddress[] destinatarios = null;
		String[] enderecosToArray = null;

		InternetAddress[] ccs = null;
		String[] ccsToArray = null;

		javax.mail.Authenticator authenticator = new javax.mail.Authenticator() {
			protected PasswordAuthentication getPasswordAuthentication() {
				return new PasswordAuthentication(emailVO.getUsuarioEmail(), emailVO.getSenhaUsuarioEmail());
			}
		};

		Properties properties = new Properties();
		properties.setProperty("mail.smtp.submitter", emailVO.getUsuarioEmail());

		boolean usaAutenticacao = emailVO.getUsuarioEmail() != null && !emailVO.getUsuarioEmail().equals("");

		/*
		 * Se o e-mail for enviado com autenticação, coloca as informações de
		 * usuário e senha
		 */
		if (usaAutenticacao) {
			properties.put("mail.smtp.auth", "true");
		}

		/*
		 * Coloca configurações de segurança, se o e-mail utilizar SSL.
		 */
		if (emailVO.isUsaSSL()) {
			properties.put("mail.smtp.socketFactory.port", emailVO.getPortaEmail());
			properties.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
		}

		properties.setProperty("mail.smtp.host", emailVO.getServidorEmail());
		properties.setProperty("mail.smtp.port", emailVO.getPortaEmail());

		Session session = Session.getInstance(properties, authenticator);
		session.setDebug(true);

		MimeMessage message = new MimeMessage(session);
		enderecosToArray = emailVO.getEnderecosToArray();
		destinatarios = new InternetAddress[enderecosToArray.length];
		for (int i = 0; i < destinatarios.length; i++) {
			destinatarios[i] = new InternetAddress(enderecosToArray[i]);
		}
		message.setRecipients(Message.RecipientType.TO, destinatarios);

		ccsToArray = emailVO.getccsToArray();
		ccs = new InternetAddress[ccsToArray.length];
		for (int i = 0; i < ccs.length; i++) {
			ccs[i] = new InternetAddress(ccsToArray[i]);
		}
		message.setRecipients(Message.RecipientType.CC, ccs);
		message.setFrom(new InternetAddress(emailVO.getEnderecoFrom()));
		message.setSubject(MimeUtility.encodeText(emailVO.getSubtitulo()));

		message.setContent(emailVO.getCorpoEmail(), emailVO.getContentType());

		if (emailVO.isSolicitaConfirmacao()) {
			message.setHeader("Disposition-Notification-To", emailVO.getEnderecoFrom());
		}

		Transport.send(message, message.getAllRecipients());
	}

	/**
	 * Obtém as configurações de envio do email.
	 * 
	 * @param email
	 * @return
	 * @throws ChamatecNegocioException
	 */
	public static EmailVO obterConfiguracoesEmail(EmailVO email) throws ChamatecNegocioException {
		email.setServidorEmail(getProperty("HOST_SERVIDOR_EMAIL_AUTORIZ"));
		email.setPortaEmail(getProperty("PORTA_SERVIDOR_EMAIL_AUTORIZ"));
		email.setContentType(getProperty("CONTENT_TYPE_EMAIL_AUTORIZ"));
		email.setEnderecoFrom(getProperty("EMAIL_AUTORIZ"));
		email.setUsuarioEmail(getProperty("EMAIL_AUTORIZ_LOGIN"));
		email.setSenhaUsuarioEmail(decrypt(getProperty("EMAIL_AUTORIZ_PASSWORD")));
		email.setUsaTLS(Boolean.valueOf(getProperty("EMAIL_UTILIZA_TLS")));
		email.setUsaSSL(Boolean.valueOf(getProperty("EMAIL_UTILIZA_SSL")));
		email.setAceitaCertificadoInvalido(Boolean.valueOf(getProperty("EMAIL_ACEITA_CERTIFICADO_INVALIDO")));

		return email;
	}

	/**
	 * Recupera o valor da propriedade no arquivo de configuração de email.
	 * 
	 * @param property
	 * @return
	 */
	private static String getProperty(String property) {
		String retorno = null;
		if (prop == null) {
			prop = new Properties();
			try {
				prop.load(ChamatecUtil.class.getClassLoader().getResourceAsStream("smtp.properties"));
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		if (prop != null) {
			retorno = prop.getProperty(property);
		}

		return retorno;
	}

	/**
	 * Metodo para validar CPF
	 * 
	 * @param cpf
	 * @return
	 */
	public static boolean validarCPF(String cpf) {
		boolean ret = false;
		String base = "000000000";
		String digitos = "00";
		if (cpf.length() <= 11) {
			if (cpf.length() < 11) {
				cpf = base.substring(0, 11 - cpf.length()) + cpf;
				base = cpf.substring(0, 9);
			}
			base = cpf.substring(0, 9);
			digitos = cpf.substring(9, 11);
			int soma = 0, mult = 11;
			int[] var = new int[11];
			// Recebe os numeros e realiza a multiplicação e soma.
			for (int i = 0; i < 9; i++) {
				var[i] = Integer.parseInt("" + cpf.charAt(i));
				if (i < 9)
					soma += (var[i] * --mult);
			}
			// Cria o primeiro dígito verificador.
			int resto = soma % 11;
			if (resto < 2) {
				var[9] = 0;
			} else {
				var[9] = 11 - resto;
			}
			// Reinicia os valores.
			soma = 0;
			mult = 11;
			// Realiza a multiplicação e soma do segundo dígito.
			for (int i = 0; i < 10; i++)
				soma += var[i] * mult--;
			// Cria o segundo dígito verificador.
			resto = soma % 11;
			if (resto < 2) {
				var[10] = 0;
			} else {
				var[10] = 11 - resto;
			}
			if ((digitos.substring(0, 1).equalsIgnoreCase(new Integer(var[9]).toString())) && 
				(digitos.substring(1, 2).equalsIgnoreCase(new Integer(var[10]).toString()))) {
				ret = true;
			}
		}
		if (ret) {
			ret = validarCPFEspecifico(cpf);
		}
		return ret;
	}

	/**
	 * Valida os cpf com todos os números iguais.
	 * 
	 * @param cpf
	 * @return
	 */
	private static boolean validarCPFEspecifico(String cpf) {
		if (cpf.equals("11111111111") || cpf.equals("22222222222") || cpf.equals("33333333333") ||
			cpf.equals("44444444444") || cpf.equals("55555555555") || cpf.equals("66666666666") ||
			cpf.equals("77777777777") || cpf.equals("88888888888") || cpf.equals("99999999999") ||
			cpf.equals("00000000000")) {
			return false;
		}
		return true;
	}

	/**
	 * Formata o campo de CPF no padrão 999.999.999-99.
	 * 
	 * @param cpf
	 * @return
	 */
	public static String formataCPF(String cpf) {
		String retorno = "";
		if (cpf != null && cpf.length() == 11) {
			retorno = cpf.substring(0, 3) + "." + cpf.substring(3, 6) + "." + cpf.substring(6, 9) + "-" + cpf.substring(9, 11);
		}
		return retorno;
	}

	/**
	 * Realiza a encriptação de uma mensagem.
	 * 
	 * @param message
	 * @return
	 * @throws ChamatecNegocioException
	 */
	@SuppressWarnings("restriction")
	public static String encrypt(String message) throws ChamatecNegocioException {
		KeySpec keySpec = new PBEKeySpec(passPhrase.toCharArray(), salt, iterationCount);
		SecretKey key;
		try {
			key = SecretKeyFactory.getInstance("PBEWithMD5AndDES").generateSecret(keySpec);
			Cipher ecipher = Cipher.getInstance(key.getAlgorithm());
			AlgorithmParameterSpec paramSpec = new PBEParameterSpec(salt, iterationCount);
			ecipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);

			byte[] utf8 = message.getBytes("UTF8");
			byte[] enc = ecipher.doFinal(utf8);
			return new sun.misc.BASE64Encoder().encode(enc);
		} catch (InvalidKeySpecException e) {
			throw new ChamatecNegocioException(e);
		} catch (NoSuchAlgorithmException e) {
			throw new ChamatecNegocioException(e);
		} catch (NoSuchPaddingException e) {
			throw new ChamatecNegocioException(e);
		} catch (InvalidKeyException e) {
			throw new ChamatecNegocioException(e);
		} catch (InvalidAlgorithmParameterException e) {
			throw new ChamatecNegocioException(e);
		} catch (UnsupportedEncodingException e) {
			throw new ChamatecNegocioException(e);
		} catch (IllegalBlockSizeException e) {
			throw new ChamatecNegocioException(e);
		} catch (BadPaddingException e) {
			throw new ChamatecNegocioException(e);
		}
	}

	/**
	 * Realiza a decriptação de uma mensagem.
	 * 
	 * @param message
	 * @return
	 * @throws ChamatecNegocioException
	 */
	@SuppressWarnings("restriction")
	public static String decrypt(String message) throws ChamatecNegocioException {
		byte[] salt = { (byte) 0xA9, (byte) 0x9B, (byte) 0xC8, (byte) 0x32, (byte) 0x56, (byte) 0x34, (byte) 0xE3, (byte) 0x03 };
		int iterationCount = 19;
		KeySpec keySpec = new PBEKeySpec(passPhrase.toCharArray(), salt, iterationCount);
		SecretKey key;
		try {
			key = SecretKeyFactory.getInstance("PBEWithMD5AndDES").generateSecret(keySpec);
			Cipher dcipher = Cipher.getInstance(key.getAlgorithm());
			// Prepare the parameters to the cipthers
			AlgorithmParameterSpec paramSpec = new PBEParameterSpec(salt, iterationCount);
			dcipher.init(Cipher.DECRYPT_MODE, key, paramSpec);

			// Decode base64 to get bytes
			byte[] dec = new sun.misc.BASE64Decoder().decodeBuffer(message);
			// Decrypt
			byte[] utf8 = dcipher.doFinal(dec);
			// Decode using utf-8
			return new String(utf8, "UTF8");
		} catch (InvalidKeySpecException e) {
			throw new ChamatecNegocioException(e);
		} catch (NoSuchAlgorithmException e) {
			throw new ChamatecNegocioException(e);
		} catch (NoSuchPaddingException e) {
			throw new ChamatecNegocioException(e);
		} catch (InvalidKeyException e) {
			throw new ChamatecNegocioException(e);
		} catch (InvalidAlgorithmParameterException e) {
			throw new ChamatecNegocioException(e);
		} catch (IOException e) {
			throw new ChamatecNegocioException(e);
		} catch (IllegalBlockSizeException e) {
			throw new ChamatecNegocioException(e);
		} catch (BadPaddingException e) {
			throw new ChamatecNegocioException(e);
		}
	}

	/**
	 * Converte uma String para um valor BigDecimal, caso não seja um valor válido retorna 0.
	 *  
	 * @param value
	 * @return
	 */
	public static BigDecimal convertParaBigDecimal(String value) {
		BigDecimal retorno = null;
		try {
			retorno = new BigDecimal(value);
		} catch (Exception e) {
			retorno = BigDecimal.valueOf(0.0);
		}
		return retorno;
	}

	/**
	 * Gera uma hash MD5 a partir de um valor informado.
	 * 
	 * @param value
	 * @return
	 * @throws ChamatecNegocioException
	 */
	public static String generateMD5(String value) throws ChamatecNegocioException {
		String retorno = null;
		MessageDigest md;
		try {
			md = MessageDigest.getInstance("MD5");
			md.update(value.getBytes());

			byte byteData[] = md.digest();

			StringBuffer sb = new StringBuffer();
			for (int i = 0; i < byteData.length; i++) {
				sb.append(Integer.toString((byteData[i] & 0xff) + 0x100, 16).substring(1));
			}

			retorno = sb.toString();
		} catch (NoSuchAlgorithmException e) {
			throw new ChamatecNegocioException(e);
		}

		return retorno;
	}
}